from typing import Any

from django.db.models import Q
from rest_framework import viewsets, mixins
from rest_framework.parsers import MultiPartParser, JSONParser, FileUploadParser

from common.response import JsonResponse


class ReadOnlyModelViewSet(viewsets.ReadOnlyModelViewSet):
    """修改只读模型视图类"""
    parser_classes = [MultiPartParser, JSONParser, FileUploadParser]

    def retrieve(self, request, *args, **kwargs):
        instance = self.get_object()
        serializer = self.get_serializer(instance)
        return JsonResponse(data=serializer.data)

    def get_search_data(self, request_data: dict) -> (
            bool, Any):
        """
        获取请求数据
        """
        return True, {}

    def list(self, request, *args, **kwargs):
        ok, data = self.get_search_data(request.query_params)
        if ok is False:
            return JsonResponse(success=False, msg=str(data))

        if isinstance(data, dict):
            data = Q(**data)
        elif not isinstance(data, Q):
            data = Q()

        queryset = self.filter_queryset(self.get_queryset().filter(data))

        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data)

        serializer = self.get_serializer(queryset, many=True)
        return JsonResponse(data=serializer.data)


class ModelViewSet(ReadOnlyModelViewSet,
                   mixins.CreateModelMixin,
                   mixins.UpdateModelMixin,
                   mixins.DestroyModelMixin):
    """django模型CURD视图类"""

    def before_create(self, request) -> (bool, Any):
        return True, request.data

    def create(self, request, *args, **kwargs):
        ok, request_data = self.before_create(request)
        if ok is False:
            return JsonResponse(success=False, msg=str(request_data))

        serializer = self.get_serializer(data=request_data)
        if serializer.is_valid() is False:
            return JsonResponse(success=False, msg=str(serializer.errors))

        self.perform_create(serializer)
        headers = self.get_success_headers(serializer.data)
        return JsonResponse(data=serializer.data, headers=headers)

    def before_update(self, request, instance):
        return True, request.data

    def update(self, request, *args, **kwargs):
        partial = kwargs.pop('partial', True)
        instance = self.get_object()

        ok, request_data = self.before_update(request, instance)
        if ok is False:
            return JsonResponse(success=False, msg=str(request_data))

        serializer = self.get_serializer(instance, data=request_data, partial=partial)
        if serializer.is_valid() is False:
            return JsonResponse(success=False, msg=str(serializer.errors))

        self.perform_update(serializer)

        if getattr(instance, '_prefetched_objects_cache', None):
            # If 'prefetch_related' has been applied to a queryset, we need to
            # forcibly invalidate the prefetch cache on the instance.
            instance._prefetched_objects_cache = {}

        return JsonResponse(data=serializer.data)

    def destroy(self, request, *args, **kwargs):
        instance = self.get_object()
        self.perform_destroy(instance)
        return JsonResponse()

    def perform_destroy(self, instance):
        if hasattr(instance, "is_deleted"):
            instance.is_deleted = True
            instance.save()
        else:
            instance.delete()
